﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using Socium.Domain.Collections;
using Socium.Domain.Tests.Sociometric;
using Socium.Presentation;

namespace Socium.Tests.Procedures {
	class ProcedureViewModel : FormViewModel<Procedure> {
		#region Constructors

		public ProcedureViewModel(Procedure procedure) : base(procedure) {
			InitializeCollection();
			InitializeNewItemCommand();
		}

		public ProcedureViewModel() {
			InitializeCollection();
			InitializeNewItemCommand();
		}

		#endregion

		#region Editable properties

		string _name;

		public string Name {
			get { return _name; }
			set {
				_name = value;
				OnPropertyChanged("Name");
			}
		}

		string _description;

		public string Description {
			get { return _description; }
			set {
				_description = value;
				OnPropertyChanged("Description");
			}
		}

		void InitializeProperties(Procedure procedure) {
			Name = procedure.Name;
			Description = procedure.Description;
		}

		#endregion

		#region Election criterias

		readonly ObservableCollection<ElectionCriteriaLineItem> _items =
			new ObservableCollection<ElectionCriteriaLineItem>();

		readonly ICollection<ElectionCriteriaLineItem> _deleted_items = 
			new LinkedList<ElectionCriteriaLineItem>();

		public ICollection<ElectionCriteriaLineItem> Items {
			get { return _items; }
		}

		void InitializeCollection() {
			_items.CollectionChanged += OnCollectionChanged;
		}

		void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
			if (e.NewItems != null) {
				foreach (ElectionCriteriaLineItem new_item in e.NewItems) {
					new_item.RequestDelete += OnItemRequestDelete;
				}
			}

			if (e.OldItems != null) {
				foreach (ElectionCriteriaLineItem old_item in e.OldItems) {
					old_item.RequestDelete -= OnItemRequestDelete;
				}
			}
		}

		void OnItemRequestDelete(ElectionCriteriaLineItem line_item) {
			_deleted_items.Add(line_item);
			_items.Remove(line_item);
		}

		void InitializeItems(IEnumerable<ElectionCriteria> criterias) {
			var items =
				from criteria in criterias
				select new ElectionCriteriaLineItem(criteria);

			_items.AddRange(items);
		}

		#endregion

		#region New criteria

		public ICommand NewCriteriaCommand { get; private set; }

		void InitializeNewItemCommand() {
			NewCriteriaCommand = new Command(NewElectionCriteria);
		}

		void NewElectionCriteria() {
			var view_model = new ElectionCriteriaLineItem();
			_items.Add(view_model);
		}

		#endregion

		#region Save

		protected override void Save(Procedure model) {
			model.Name = _name;
			model.Description = _description;

			var criterias = model.ElectionCriterias;

			foreach (var deleted_item in _deleted_items) {
				deleted_item.Delete(criterias);
			}

			foreach (var item in _items) {
				item.Save(criterias);
			}
		}

		protected override string GetDisplayName(Procedure model) {
			return model.Name;
		}

		protected override string GetDefaultDisplayName() {
			return "New procedure";
		}

		protected override Procedure CreateModel() {
			return new Procedure();
		}

		protected override void Update(Procedure model) {
			InitializeProperties(model);
			InitializeItems(model.ElectionCriterias);
		}

		public override bool CanSave() {
			if (string.IsNullOrEmpty(_name)) {
				return false;
			}

			if (_items.Count == 0) {
				return false;
			}

			if (_items.Any(item => !item.CanSave())) {
				return false;
			}

			return true;
		}

		#endregion
	}
}
